/*
 * XQueryResource.java
 */

package xq.api;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import xq.util.IntRange;
import xq.util.resource.Resource;
import xq.util.resource.TextResource;

/**
 *
 * @author ThorntonRP
 */
public class XQueryResource implements Resource<String> {

	private static final long serialVersionUID = -7708694557973943770L;
	
	public static enum Type {
		MAIN,
		VARIABLES,
		FUNCTIONS,
		NAMESPACES
	}

	private final XQuery xquery;
	private final XQueryResource parentResource;
	private final TextResource textResource;
	private final Type type;
	
	private IntRange charOffsets;
	private IntRange lineOffsets;
	private Set<XQueryResource> childResources;

	XQueryResource(XQuery xquery, XQueryResource parentResource, TextResource textResource, Type type) {
		this.xquery = xquery;
		this.parentResource = parentResource;
		this.textResource = textResource;
		this.type = type;
		if (parentResource != null) {
			parentResource.addChildResource(this);
		}
	}

	/*--------------------------------------------------------------------
	 * Accessors
	 *--------------------------------------------------------------------*/
	
	public Type getType() {
		return type;
	}

	public IntRange getCharOffsets() {
		return charOffsets;
	}

	public XQueryResource getResourceAtLine(int lineNumber) {
		XQueryResource result = null;
		if (getLineOffsets().contains(lineNumber)) {
			if (childResources != null) {
				for (XQueryResource resource : childResources) {
					result = resource.getResourceAtLine(lineNumber);
					if (result != null) {
						return result;
					}
				}
			}
			result = this;
		}
		return result;
	}
	
	void setCharOffsets(IntRange charOffsets) {
		if (this.charOffsets != null) {
			throw new IllegalStateException("Property \"charOffsets\" has already been initialized.");
		}
		this.charOffsets = charOffsets;
	}

	public IntRange getLineOffsets() {
		if (lineOffsets == null) {
			initLineOffsets();
		}
		return lineOffsets;
	}

	public Set<XQueryResource> getChildResources() {
		if (childResources == null) {
			return Collections.emptySet();
		} else {
			return Collections.unmodifiableSet(childResources);
		}
	}
	
	void addChildResource(XQueryResource childResource) {
		if (childResources == null) {
			childResources = new LinkedHashSet<XQueryResource>();
		}
		childResources.add(childResource);
	}
	
	/*--------------------------------------------------------------------
	 * Resource Implementation
	 *--------------------------------------------------------------------*/
	
	public File getResourceFile() {
		return textResource.getResourceFile();
	}

	public URL getResourceURL() {
		return textResource.getResourceURL();
	}

	public URI getResourceURI() {
		return textResource.getResourceURI();
	}

	public String getContent() throws IOException {
		return textResource.getContent();
	}

	public String getContentType() {
		return "text/xquery";
	}

	/*--------------------------------------------------------------------
	 * Object Overrides
	 *--------------------------------------------------------------------*/
	
	@Override
	public String toString() {
		return getClass() + "[" + getResourceURL().toString() + "]";
	}
	
	/*--------------------------------------------------------------------
	 * Private Implementations
	 *--------------------------------------------------------------------*/
	
	private synchronized void initLineOffsets() {
		if (lineOffsets == null) {
			if (charOffsets == null) {
				throw new IllegalStateException("Property \"charOffsets\" has not been initialized.");
			} else {
				String queryText = xquery.getQueryText();
				int startLine = 0;
				int endLine = 0;
				int index = 0;
				while ((index = queryText.indexOf('\n', index + 1)) != -1 && index < charOffsets.getStart()) {
					startLine++;
				}
				endLine = startLine;
				while ((index = queryText.indexOf('\n', index + 1)) != -1 && index < charOffsets.getEnd()) {
					endLine++;
				}
				endLine++;
				lineOffsets = new IntRange(startLine, true, endLine, true);
			}
		}
	}
}
